package com.xh.hongaicodegenerator.ai.tools;

import cn.hutool.json.JSONObject;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.agent.tool.ToolMemoryId;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;

import static com.xh.hongaicodegenerator.langgraph4j.node.CodeGeneratorNode.escapeCurlyWithHint;

/**
 * NPM安装工具
 * 支持AI通过工具调用的方式执行npm install命令
 */
@Slf4j
@Component
public class NpmInstallTool extends BaseTool {

    @Tool("执行 npm install 命令安装Vue项目依赖")
    public String installDependencies(@ToolMemoryId Long appId) {
        try {
            // 构建项目目录路径
            String projectDirName = "vue_project_" + appId;
            String projectRootPath = System.getProperty("user.dir") + File.separator +
                    "tmp" + File.separator + "code_output" + File.separator + projectDirName;
            File projectDir = new File(projectRootPath).getCanonicalFile();

            if (!projectDir.exists() || !projectDir.isDirectory()) {
                return "错误：项目不存在";
            }

            // 检查package.json是否存在
            File packageJsonFile = new File(projectDir, "package.json");
            if (!packageJsonFile.exists()) {
                return "错误：项目目录中没有找到 package.json 文件";
            }

            log.info("在目录 {} 中执行 npm install 命令", projectDir.getAbsolutePath());

            // 根据操作系统选择正确的npm命令
            String[] command = getNpmCommand("install");

            // 执行 npm install 命令并捕获输出
            Process process = Runtime.getRuntime().exec(command, null, projectDir);
            StringBuilder errorOutput = new StringBuilder();

            // 读取标准输出
            BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            Thread errorThread = new Thread(() -> {
                try {
                    String line;
                    while ((line = stdError.readLine()) != null) {
                        errorOutput.append(line).append("\n");
                    }
                } catch (Exception e) {
                    log.error("读取错误输出时出错: {}", e.getMessage());
                }
            });

            errorThread.start();

            // 等待进程完成，设置超时时间（10分钟）
            boolean finished = process.waitFor(600, TimeUnit.SECONDS);
            if (!finished) {
                log.error("npm install 命令执行超时，强制终止进程");
                process.destroyForcibly();
                return "错误：npm install 命令执行超时，请检查代码是否有误";
            }

            // 等待输出读取线程完成
            errorThread.join(5000);  // 等待最多5秒

            int exitCode = process.exitValue();

            if (exitCode == 0) {
                log.info("npm install 命令执行成功");
                return "依赖安装成功完成";
            } else {
                log.error("npm install 命令执行失败，退出码: {}", exitCode);
                // 安装失败时返回详细信息
                String errorResult = errorOutput.toString();
                // 过滤和脱敏错误信息
                String filteredError = filterAndDesensitizeError(errorResult, projectRootPath);
                StringBuilder result = new StringBuilder();
                if (!filteredError.isEmpty()) {
                    result.append("依赖安装失败，错误输出为:\n").append(filteredError).append("\n");
                }
                return result.toString();
            }
        } catch (Exception e) {
            String errorMessage = "执行npm install命令失败: " + e.getMessage();
            log.error(errorMessage, e);
            return escapeCurlyWithHint(errorMessage);
        }
    }

    /**
     * 过滤和脱敏错误信息
     * @param errorOutput 错误输出
     * @param projectRootPath 项目根路径
     * @return 过滤和脱敏后的错误信息
     */
    private String filterAndDesensitizeError(String errorOutput, String projectRootPath) {
        if (errorOutput == null || errorOutput.isEmpty()) {
            return "";
        }
        // 使用replace将项目根路径替换为空字符串，实现脱敏
        String filteredOutput = errorOutput.replace(projectRootPath + "/", "");

        return escapeCurlyWithHint(filteredOutput.toString());
    }

    /**
     * 根据操作系统返回正确的npm命令
     * @param args npm命令参数
     * @return 正确的命令数组
     */
    private String[] getNpmCommand(String... args) {
        String npmCommand = isWindows() ? "npm.cmd" : "npm";
        String[] command = new String[1 + args.length];
        command[0] = npmCommand;
        System.arraycopy(args, 0, command, 1, args.length);
        return command;
    }

    /**
     * 判断是否为Windows系统
     * @return 是否为Windows系统
     */
    private boolean isWindows() {
        String osName = System.getProperty("os.name").toLowerCase();
        return osName.contains("windows");
    }

    @Override
    public String getToolName() {
        return "installDependencies";
    }

    @Override
    public String getDisplayName() {
        return "安装依赖";
    }

    @Override
    public String generateToolExecutedResult(JSONObject arguments) {
        return String.format("[工具调用] %s", getDisplayName());
    }
}
